Visualização de dados

Faremos alguns gráficos para visualização de dados. Para isso importaremos os seguinte pacotes:

# Importando bibliotecas
library(tidyverse)
library(plotly)
library(scales)
library(ggsci)     # permite obter paletas de cores oficiais de revistas ciêntíficas e relacionadas à cultura de ficção ciêntífica
library(patchwork) # permite combinar gráficos do pacote ggplot2 em uma mesma figura

População brasileira por sexo

Vamos trabalhar com um conjunto de dados referente à quantidade de habitantes da população brasileira segundo sexo e grupo de idade em uma série histórica de 2012 a 2019. Esse conjunto foi baixado através do pacote basedosdados. Foram feitas algumas modificações no conjunto (observe o script tidyingdata_1.R) para ter os dados no formato tidy. Então vamos carregar os dados:

dt <- readr::read_csv('dados/populacao_brasil_pnadc_tidy.csv')
glimpse(dt)
## Rows: 256
## Columns: 4
## $ ano         <dbl> 2012, 2012, 2012, 2012, 2012, 2012, 2012, 2012, 2012, 2012…
## $ sexo        <chr> "Homens", "Homens", "Homens", "Homens", "Homens", "Homens"…
## $ grupo_idade <chr> "0 a 4 anos", "5 a 13 anos", "5 a 9 anos", "10 a 13 anos",…
## $ populacao   <dbl> 6812000, 14163000, 7369000, 6794000, 7217000, 3587000, 363…

Os gráficos p1_a e p1_b irão mostrar o número de habitantes por sexo em cada ano, já que usaremos facet_wrap() para dividir os dados em subgráficos. Antes disso, precisamos obter o total de habitantes de cada sexo para cada ano, já que nossos dados estão divididos em grupos de idade. Isso requer que façamos a soma do número de habitantes, agrupando por sexo e ano. Trata-se de uma operação de sumarização de dados que pode ser feita usando summarise() e o parâmetro .by. No entanto, nossos dados tem redundância em alguns grupos de idade, ou seja, alguns níveis englobam habitantes por idade de outros níveis, causando interseção entre os níveis. Portanto, devemos filtrar alguns grupos de idade específicos para obter uma sumarização coerente (faremos isso com a função filter()).

grupos_redundantes <- c('5 a 13 anos', '14 a 17 anos', '60 anos ou mais')
p1_a <- dt |>
        filter(!(grupo_idade %in% grupos_redundantes)) |>
        summarise(total = sum(populacao), .by = c(sexo, ano)) |>
        ggplot(aes(x = ano, y = total, fill = sexo)) +
        geom_col() +
        facet_wrap(~sexo)
p1_b <- dt |>
  filter(!(grupo_idade %in% grupos_redundantes)) |>
  summarise(total = sum(populacao), .by = c(sexo, ano)) |>
  ggplot(aes(x = ano, y = total / 10^6, fill = sexo)) +
  geom_col() +
  facet_wrap(~sexo)
p1_a / p1_b # mostrar os plots p1_a e p1_b

Perceba que nem todos os anos aparecem no eixo x. Portanto, faremos uma alteração usando a função scale_x_continuous() e o parâmetro breaks para indicar como labels do eixo x todos os anos da série histórica - serão obtidas as ocorrências únicas dos anos na coluna ano através da função unique() do pacote base. Também adicionaremos um tema.

p1_a + scale_x_continuous(breaks = unique(dt$ano)) + theme_classic()

Os valores do eixo y estão em notação ciêntifica, o que não é amigável para o gráfico pretendido. Vamos alterar o eixo y para mostrar o número de habitantes em notação numérica, ao invés de ciêntifica, usando scale_y_continuous() e scales::label_comma().

p1_a <- p1_a +
  scale_x_continuous(breaks = unique(dt$ano)) +
  scale_y_continuous(labels = label_comma(big.mark = '.', decimal.mark = ',')) +
  theme_classic()
p1_a

Em p1_b também geraremos notação numérica, no entanto, em milhões de habitantes usando scale_y_continuous() e scales::number_format().

p1_b <- p1_b +
    scale_x_continuous(breaks = unique(dt$ano)) +
    scale_y_continuous(labels = number_format(suffix = "M")) +
    theme_classic()
p1_b

Agora alteraremos o título do eixo y e excluíremos do eixo x.

p1 <- p1_a + ylab("População Brasileira") + theme(axis.title.x = element_blank())
p1

Podemos converter p1 para um gráfico interativo com ggplotly().

ggplotly(p1)

Vejamos a construção de um gráfico interativo que apresentará a mesma informação. Porém, usaremos somente o plot_ly().

dt |>
  filter(!(grupo_idade %in% grupos_redundantes)) |>
  summarise(total = sum(populacao), .by = c(sexo, ano)) |>
  plot_ly(x = ~ano, 
          y = ~total,
          color = ~sexo,
          type = 'bar') |>
  layout(yaxis = list(title = "População Brasileira"),
         xaxis = list(title = ""))
# group_by(sexo) |>
# group_map(~ plot_ly(data=., x = ~ano, y = ~total, color = ~sexo, type = "bar"), .keep=TRUE) |>
# subplot(nrows = 1, shareX = TRUE, shareY=TRUE)

Exercício

Gere um gráfico de linhas e pontos com o ggplot2 para a população brasileira diferenciando pela coluna sexo e faça a converção para um gráfico interativo com ggplotly().

p1 <- dt |>
  filter(!(grupo_idade %in% grupos_redundantes)) |>
  summarise(total = sum(populacao), .by = c(sexo, ano)) |>
  ggplot(aes(x = ano, y = total * 10^-6, color = sexo)) +
  geom_line() + 
  geom_point() +
  ylab("População Brasileira (milhões)") + theme(axis.title.x = element_blank())
p1

ggplotly(p1)
# ou usando apenas o plotly
dt |>
  filter(!(grupo_idade %in% grupos_redundantes)) |>
  summarise(total = sum(populacao), .by = c(sexo, ano)) |>
  plot_ly(x = ~ano, 
          y = ~total,
          color = ~sexo,
          type = "scatter",
          mode = "line+marker") |>
  layout(yaxis = list(title = "População Brasileira"),
         xaxis = list(title = ""))
## Warning in RColorBrewer::brewer.pal(N, "Set2"): minimal value for n is 3, returning requested palette with 3 different levels

## Warning in RColorBrewer::brewer.pal(N, "Set2"): minimal value for n is 3, returning requested palette with 3 different levels

População brasileira por grupo de idade

Vamos produzir um gráfico dos habitantes considerando a coluna grupo_idade. Para isso geramos subgráficos usando facet_wrap(). Faremos ajustes no texto do eixo x e dos paíneis de cada subgráfico para melhorar a visualização.

dt |>
  filter(!(grupo_idade %in% grupos_redundantes)) |>
  #filter(sexo == "Mulheres") |>
  #filter(sexo == "Homens") |>
  ggplot(aes(ano, populacao)) +
  geom_col() +
  facet_wrap(sexo ~ grupo_idade, nrow = 2) +
  theme_classic() +
  theme(axis.text.x = element_text(angle = 60, hjust = .9),
        strip.text.x = element_text(margin = margin(.1,.2,.1,.2, "cm")))

Perceba que os grupos de idade não estão dispostos em uma ordenação amigável. Vamos converter a coluna grupo_idade de character para o tipo factor, mas aplicando uma ordenação manual através de duas alternativas:

  • Alternativa 1 - criar um conjunto de labels pré-ordenados - contendo níveis existentes da coluna grupo_idade - e indicá-lo como níveis ao converter para variável categórica através do parâmetro levels da função factor();
  • Alternativa 2 - usar a função forcats::fct_reorder() para reordenar os dados baseado nos valores de outra coluna.

Além disso, geraremos os subgráficos usando face_grid() que permite um controle sobre à disposição dos labels nos eixos x e y.

faixa_etaria_labels = c("0 a 4 anos", "5 a 9 anos", "5 a 13 anos", "10 a 13 anos", "14 a 15 anos",
                        "14 a 17 anos", "16 a 17 anos",    "18 a 19 anos",    "20 a 24 anos",
                        "25 a 29 anos", "30 a 39 anos", "40 a 49 anos", "50 a 59 anos",
                        "60 a 64 anos", "60 anos ou mais", "65 anos ou mais")
p2 <- dt |>
  filter(!(grupo_idade %in% grupos_redundantes)) |>
  mutate(grupo_idade = factor(grupo_idade, levels = faixa_etaria_labels)) |>          # alternativa 1
  #mutate(grupo_idade = fct_reorder(factor(grupo_idade), populacao)) |>               # alternativa 2
  ggplot(aes(x = ano, y = populacao * 10^-6, fill = sexo)) +
  geom_col() +
  facet_grid(sexo ~ grupo_idade) +
  ylab("População Brasileira (milhões de habitantes)") +
  theme_classic()
# Criando um tema com modificações de elementos gráficos
mytheme <- theme(legend.position = "top", legend.title = element_blank(),
                 legend.text = element_text(size = 15, family = 'arial', color = 'black'),
                 axis.title.y = element_text(size = 18, family = 'arial', color = 'black'),
                 axis.title.x = element_blank(),
                 axis.text.y = element_text(size = 15, family = 'arial'),
                 axis.text.x = element_text(size = 15, family = 'arial', angle = 65, vjust = .5),
                 strip.text.y = element_text(size = 13, family = 'arial', color = 'black'),
                 strip.text.x = element_text(size = 9.5, family = 'arial', color = 'black', margin = margin(.1,.4,.1,.4, "cm")))
p2

p2 + mytheme

ggplotly(p2 + theme(legend.position = 'none', axis.text.x = element_text(angle = 65, vjust = .5)))

Podemos criar gráficos similares usando plot_ly().

dt |>
    filter(!(grupo_idade %in% grupos_redundantes)) |>
    mutate(grupo_idade = factor(grupo_idade, levels = faixa_etaria_labels)) |>          # alternativa 1
    #mutate(grupo_idade = fct_reorder(factor(grupo_idade), populacao)) |>               # alternativa 2
    group_by(sexo, grupo_idade) |>
    plot_ly(x = ~ano, 
            y = ~populacao,
            color = ~sexo,
            split = ~grupo_idade,
            type = "bar") |>
    layout(yaxis = list(title = "População Brasileira"),
           xaxis = list(title = ""))
## Warning in RColorBrewer::brewer.pal(N, "Set2"): minimal value for n is 3, returning requested palette with 3 different levels

## Warning in RColorBrewer::brewer.pal(N, "Set2"): minimal value for n is 3, returning requested palette with 3 different levels
dt |>
    filter(!(grupo_idade %in% grupos_redundantes)) |>
    #mutate(grupo_idade = factor(grupo_idade, levels = faixa_etaria_labels)) |>        # alternativa 1
    mutate(grupo_idade = fct_reorder(factor(grupo_idade), populacao)) |>               # alternativa 2
    group_by(grupo_idade) |>
    group_map(~ plot_ly(data=., 
                        x = ~ano, 
                        y = ~populacao, 
                        color = ~sexo, 
                        split = ~sexo, 
                        name = ~grupo_idade,
                        type = "bar"), .keep=TRUE) |>
    subplot(nrows = 1, shareX = TRUE, shareY=TRUE, titleX = FALSE) |>
    layout(yaxis = list(title = "População Brasileira"))

Exercício

Gere um gráfico de linhas e pontos com o ggplot2 para a população brasileira diferenciando por grupo de idade. O gráfico deve conter sub-divisões dos dados por sexo (subgráficos). Faça a conversão para um gráfico interativo com ggplotly().

p2 <- dt |>
  filter(!(grupo_idade %in% grupos_redundantes)) |>
  mutate(grupo_idade = factor(grupo_idade, levels = faixa_etaria_labels)) |>          # alternativa 1
  #mutate(grupo_idade = fct_reorder(factor(grupo_idade), populacao)) |>               # alternativa 2
  ggplot(aes(x = ano, y = populacao * 10^-6, color = grupo_idade)) +
  geom_line() + geom_point() +
  facet_wrap(~sexo) +
  ylab("População Brasileira (milhões de habitantes)") +
  theme_classic() 
ggplotly(p2)

Taxa de desocupação da população brasileira

Vamos ler a série histórica da PNAD Contínua referente à taxa de desocupação da população brasileira por grupo de idade entre 2012 e 2023. Esses dados foram baixados diretamente do site do IBGE. Foi feita uma limpeza no conjunto de dados original para obter o formato tidy (observe o script tidyingdata_2.R ).

dt <- readr::read_csv('dados/taxa_desocupacao_idade_2012-2013_tidy.csv')

É interessante visualizar a taxa de desocupação por meio de gráfico de linhas para observar a variação a cada trimestre. No entanto, temos apenas a coluna trimestre como variável categórica e ordena-la da forma mais adequada será complicado usando apenas essa coluna. Portando, extraíremos o ano dos valores da coluna trimestre para produzir uma nova coluna que vai permitir a ordenação de forma mais prática.

p3 <- dt |>
  mutate(ano = as.numeric(str_sub(trimestre, nchar(trimestre) -3, nchar(trimestre)))) |>
  mutate(trimestre = fct_reorder(factor(trimestre), ano)) |>
  ggplot(aes(x = trimestre, y = taxa_desocupacao, group = faixa_etaria, color = faixa_etaria)) +
  geom_line() +
  ylab("Taxa de Desocupação \n População Economicamente Ativa (%)") +
  scale_color_uchicago() +
  theme_classic() +
  theme(legend.title = element_blank(), axis.text.x = element_text(angle = 90), axis.title.x = element_blank())
p3

ggplotly(p3)

Podemos produzir gráficos similares com plot_ly().

dt |>
  mutate(ano = as.numeric(str_sub(trimestre, nchar(trimestre) -3, nchar(trimestre)))) |>
  mutate(trimestre = fct_reorder(factor(trimestre), ano)) |>
  plot_ly(x = ~trimestre, y = ~taxa_desocupacao, color = ~faixa_etaria, type = "scatter", mode = "lines+markers") |>
  layout(
    yaxis = list(title = 'Taxa de Desocupação \n População Economicamente Ativa (%)"'),
    xaxis = list(title = '')
  )
dt |>
  mutate(ano = as.numeric(str_sub(trimestre, nchar(trimestre) -3, nchar(trimestre)))) |>
  summarise(taxa_desocupacao = mean(taxa_desocupacao), .by = c(ano, faixa_etaria)) |>
  plot_ly(x = ~ano,
          y = ~taxa_desocupacao,
          color = ~faixa_etaria,
          type = "scatter",
          mode = "lines+markers") |>
  layout(yaxis = list(title = "Taxa de Desocupação \n População Economicamente Ativa (%)"),
         xaxis = list(title = ""))

Exercício

Leia os dados da população brasileira segundo cor da pele (tabela populacao_brasil_pnadc_cor.csv) e execute os seguinte passos:

  • Arrume esses dados para ficar no formato tidy, escrevendo o código necessário em um script ;
  • Salve os dados em um arquivo do tipo CSV;
  • Carregue os dados no formato tidy nesse R notebook;
  • Crie gráficos de linhas e pontos e, barras para visualizar os dados.